#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <string.h>
#include <stdio.h>

using namespace std;

double ecm(unsigned int N, unsigned int * img, unsigned int * imgF);
double psnr(unsigned int n, unsigned int * img, unsigned int * imgF);

void SaltearComentarios(FILE *fp);
void SaltearComentarios(FILE *fp1);


int main(int argc, char* argv[])
{ //imgOriginal, imgConRuido, lambda, fr, nr
    //argv[0] es el nombre del programa
    char* imgOrig = argv[1];
	double lambda = atof(argv[2]);
    char* imgRuido = argv[3];


 //Lectura del PGM:
    FILE* fp = fopen(strcat(imgOrig,".pgm"),"rb");
    FILE* fp1 = fopen(strcat(imgRuido,".pgm"),"rb");
    unsigned int height, width;
	int primerC, segC, max, c1, c2, c3, f, c;

    primerC = fgetc(fp);
	segC = fgetc(fp);
	SaltearComentarios(fp);
	c1 = fscanf(fp, "%d", &width);
	SaltearComentarios(fp);
	c2 = fscanf(fp, "%d", &height);
	SaltearComentarios(fp);
	c3 = fscanf(fp, "%d", &max);
	cout << "Altura:" << height << endl << "Ancho:" << width << endl;
    unsigned int* image = new unsigned int[height*width];


	if (primerC != 80 || segC != 53 || c1 != 1 || c2 != 1 || c3 != 1 || max > 255)
    {
        cout << c3 << " " << max << " " << "La imagen seleccionada no tiene formato PGM.\n" << endl;
        return 1;
    }

	fgetc(fp);//Paso de largo el caracter siguiente ya que no me interesa (segun especificacion, generalmente es un newline)
    unsigned char temp;
	for (int i = 0; i < height*width; i++)
	{
            temp = fgetc(fp);
            image[i] =  temp;
	}

	fclose(fp);

	// Lectura del otro PGM:
    unsigned int height1, width1;
 	int primerCb, segCb, maxb, c1b, c2b, c3b, fb, cb;

    primerCb = fgetc(fp1);
	segCb = fgetc(fp1);
	SaltearComentarios(fp1);
	c1b = fscanf(fp1, "%d", &width1);
	SaltearComentarios(fp1);
	c2b = fscanf(fp1, "%d", &height1);
	SaltearComentarios(fp1);
	c3b = fscanf(fp1, "%d", &maxb);
	cout << "Altura:" << height1 << endl << "Ancho:" << width1 << endl;
    unsigned int* image1 = new unsigned int[height1*width1];


	if (primerCb != 80 || segCb != 53 || c1b != 1 || c2b != 1 || c3b != 1 || maxb > 255)
    {
        cout << c3b << " " << maxb << " " << "La imagen seleccionada no tiene formato PGM.\n" << endl;
        return 1;
    }

	fgetc(fp1);//Paso de largo el caracter siguiente ya que no me interesa (segun especificacion, generalmente es un newline)
    unsigned char temp1;
	for (int i = 0; i < height1*width1; i++)
	{
            temp1 = fgetc(fp1);
            image1[i] =  temp1;
	}

	fclose(fp1);

    cout << "lambda: " << lambda <<endl;

	//PSNR:
	unsigned int N = height*width;
	double  p = psnr(N, image, image1);
	cout<< "psnr: " << p << endl;


    return 0;
}

// Funcion para calcula el ECM
double ecm(unsigned int N, unsigned int * img, unsigned int * imgF)
{
	double e = 0;
	unsigned int n = sqrt(N);

	for (unsigned int i = 0; i < n; i++)
	{
		for(unsigned int j = 0; j < n; j++)
		{
			double pOrig = double(img[i*n+j]);
			double pFilt = double(imgF[i*n+j]);
			e = e + (pOrig-pFilt)*(pOrig-pFilt);
		}
	}

	N = double(N);
	e = e/N;

	return e;
}

// Funcion para calcular el PSNR de una imagen filtrada
// n=cant de pixeles de la imagen / img=imagen original / imgF=imagen filtrada
double psnr(unsigned int N, unsigned int * img, unsigned int * imgF)
{

double E = ecm(N,img,imgF);
double p;

// comprobamos que, si img e imgF son distintas (i.e. ya con dos mismos pixeles de distinto valor), entonces E>=1/N
if (E >=(1/N))
{
	p = 10 * log10((255*255)/E);
	return p;
}
else  //E tiende a 0 (en realidad vale 0, ya que estamos en el caso en que img==imgF)
{
	p = NAN; //PSNR indefinido
	return p;
}

}

void SaltearComentarios(FILE *fp)
{
	int ch;
	char line[100];

	while ((ch = fgetc(fp)) != EOF && isspace(ch))
	{
	    ;
	}
	if (ch == '#')
	{
		fgets(line, sizeof(line), fp);
		SaltearComentarios(fp);
	}
	else
	{
        fseek(fp, -1, SEEK_CUR);
	}
}

